package com.qf.shiro;

import com.qf.pojo.DtsAdmin;
import com.qf.service.AdminService;
import com.qf.service.PermissionService;
import com.qf.service.RoleService;
import com.qf.util.bcrypt.BCryptPasswordEncoder;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.List;
import java.util.Set;

/**
 * 自定义Realm, shiro中用来对用户名密码进行校验和登录后授权
 * @author 千锋健哥
 */
public class AdminAuthorizingRealm extends AuthorizingRealm {

    @Autowired
    private AdminService adminService;

    @Autowired
    private RoleService roleService;

    @Autowired
    private PermissionService permissionService;

    /**
     * 用户登录成功后, 对用户进行授权, 授予对应的角色和权限
     * @param
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principal) {

        //1. 获取认证后的当前用户对象, 这里将参数强转成我们自己封装的用户实体类对象
        DtsAdmin admin = (DtsAdmin)getAvailablePrincipal(principal);

        //2. 根据用户对象获取角色ids
        Integer[] roleIds = admin.getRoleIds();

        //3. 根据角色id集合到数据库中查找对应的角色名称集合
        Set<String> roleSet = roleService.queryById(roleIds);

        //4. 根据角色id集合, 到数据库中查询对应的权限字符串集合
        Set<String> permSet = permissionService.queryPermissonByRoleIds(roleIds);

        //5. 将角色名称集合, 和权限字符串集合交给shiro框架
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        info.setRoles(roleSet);
        info.setStringPermissions(permSet);

        //6. 返回封装后的shiro权限对象
        return info;

    }

    /**
     * 接收页面传入的用户名密码, 根据数据库的用户名密码进行校验
     * @param token
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {

        //1、获取用户在页面中输入的用户名、密码
        UsernamePasswordToken UserNamePwdToken = (UsernamePasswordToken) token;
        String userName = UserNamePwdToken.getUsername();
        String password = new String(UserNamePwdToken.getPassword());

        //2、判断用户名是否为空，为空返回异常提示信息
        if (StringUtils.isEmpty(userName)){
            throw new AccountException("用户名为空！");
        }

        //3、判断密码是否为空、为空返回异常提示消息
        if (StringUtils.isEmpty(password)){
            throw new AccountException("密码为空！");
        }

        //4、根据用户名获取用户对象集合
        List<DtsAdmin> userList = adminService.findAdminByUserName(userName);

        //5、判断获取是否到用户对象，没有获取到用户对象，返回异常提示信息
        if (userList == null || userList.size() == 0){
            throw new UnknownAccountException("用户名有误！");
        }

        //6、判断，用户名大于1，说明已经存在同名用户，不允许登录
        if (userList.size()>=2){
            throw new UnknownAccountException("用户名已存在，请联系管理员！");
        }
        DtsAdmin admin = userList.get(0);

        //7、判断密码是否正确，错误返回异常提示信息
        BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();

        if (!encoder.matches(password, admin.getPassword())){
            throw new UnknownAccountException("密码错误！");
        }

        //8、封装shiro指定的对象类型，交给shiro框架处理
        SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(admin,password,this.getName());

        return info;
    }

}
